<?php
abstract class ModuleSns
{

    /**
     * @var int
     */
    protected $userId;
    /**
     * Platform name.
     *
     * @var string
     */
    protected $platform;
    /**
     * Platform related configs.
     * <pre>
     * Location:
     * /.../www/apps/main/latest/config/module_sns_*.config.php
     * * = platform name
     * </pre>
     *
     * @var array
     */
    protected $configs;

    /**
     * @var SzContext
     */
    protected $context;

    /**
     * Platform sdk, provided by third party platform.
     *
     * @var Object
     */
    protected $sdk;

    /**
     * Construction.
     *
     * @param int $userId
     * @param string $platform
     * @param array $configs
     */
    public function __construct($userId, $platform, $configs)
    {
        $this->userId = $userId;
        $this->platform = $platform;
        $this->configs = $configs;
        // initialize application context
        $this->context = SzContextFactory::get();
    }

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* 0. PLATFORM PAGE JS CODE
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Create page embeded js code, according to platform requirement.
     *
     * @return string $code
     */
    abstract public function createJsEmbeddedCode();

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* 1. PAGE DATA INITIALIZATION ON INDEX
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Initialize necessary params on index page according to platform, and set it into cache, for global retrieving.
     *
     * @return array '$userId => int, $platform => string'
     */
    abstract public function initializeOnIndex();

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* 2. APIs
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Get friends list (ids).
     *
     * @see ModuleSns::getPfFriends()
     * @param int $userId
     * @return array $friends array(id, id, ...)
     */
    public function getFriends($userId)
    {
        return $this->getPfFriends($userId);
    }

    /**
     * Call platform API to get user platform friend ids.
     *
     * @param int $userId player game userId
     * @return array $friends array(id, id, ...)
     */
    abstract protected function getPfFriends($userId);

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* UTILITIES
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Get platform sdk instance.
     *
     * @return Object
     */
    public function getPlatformSdk()
    {
        return $this->sdk;
    }

    /**
     * Get platform token, for example: if platform is Facebook, the token is $_REQUEST['signed_request']
     *
     * @return string
     */
    abstract public function getPfToken();

    /**
     * Get platform signature, for example: if platform is sina, the token is $_REQUEST['wyx_signature']
     *
     * @return string
     */
    abstract public function getPfSignature();

    /**
     * It's necessary to reinitialize(reset several necessary params) SDK,
     * since $_GET & $_POST array will be empty in almost all API calls between FLASH client & PHP server.
     * (At that time, the container is our REST structure FLASH/PHP, not platform game page anymore.)
     *
     * @return void
     */
    abstract protected function preparePfApiEnv();

    /**
     * Check REST result, if exception, throw it.
     * The format of $result is mixed, since it would be different according to platform return.
     *
     * @param array $result
     * @return void
     */
    abstract protected function checkResult($result);

    /**
     * Port platform id to game player user id.
     * If implementation class does not need to port id from platform id to game id,
     * it can be overwritten to just return the platform id.
     *
     * @param string $platformId
     * @param boolean $create default FALSE, whether to create port record if not exist
     * @return int $userId
     */
    public function portPlayerUserId($platformId, $create = false)
    {
        $userId = null;

        /* @var ModuleSnsVo $portVo */
        $portVo = SzPersister::get()->getVo(null, ModuleSnsConst::ORM_NAME_SNS, $platformId);
        if (!$portVo && $create) {
            /* @var SzMySqlModel $model */
            $model = SzPersister::get()->getModel(ModuleSnsConst::ORM_NAME_SNS);
            $portVo = new ModuleSnsVo($platformId, null, SzTime::getTime(), true);
            list($affected, $insertId) = $model->insert($portVo); // we need the userId to be created immediately, so insert here
            if ($insertId) {
                $userId = $insertId;
                $portVo->setUserId($userId);
                $portVo->removeInsertFlag();
                $model->setVoCache($portVo);
                SzPersister::get()->setVo($portVo);
            }
        } else if ($portVo) {
            $userId = $portVo->getUserId();
        }

        $this->userId = $userId; // set ported user id into instance

        return $userId;
    }

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CACHE
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Get cached platform info.
     *
     * @param int $userId
     * @param string $platform
     * @return array $info
     */
    public function getPfInfoCache($userId, $platform)
    {
        $info = $this->context->getStaticCache()->get("PF-{$platform}-{$userId}");
        if ($info) {
            $info = json_decode($info, true);
        }
        return $info;
    }

    /**
     * Set platform info into cache.
     *
     * @param int $userId
     * @param string $platform
     * @param array $info
     * @return boolean
     */
    protected function setPfInfoCache($userId, $platform, $info)
    {
        return $this->context->getStaticCache()->set("PF-{$platform}-{$userId}", json_encode($info));
    }

    /**
     * Get cached player friends list.
     * <pre>
     * "[id,id,...]" // in cache
     * =>
     * array(id, id, ...) // returned
     * </pre>
     *
     * @param int $userId
     * @return array $list
     */
    protected function getPfFriendsCache($userId)
    {
        $list = $this->context->getAppCache()->get("PF-FS-{$this->platform}-{$userId}");
        if ($list) {
            $list = json_decode($list, true);
        }

        return $list;
    }

    /**
     * Set player friends list into cache.
     * <pre>
     * "id,id,..." // in cache
     * <=
     * array(id, id, ...) // returned
     * </pre>
     *
     * @param int $userId
     * @param array $list array(id,id,...)
     * @return array boolean
     */
    protected function setPfFriendsCache($userId, $list)
    {
        return $this->context->getAppCache()->set("PF-FS-{$this->platform}-{$userId}", json_encode($list));
    }

    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    //-* CONFIG
    //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
    /**
     * Provide a way to load sns setting for logics outside the SNS module.
     * This function will check $this->platform and load the config file accordingly.
     *
     * @param string $key
     * @return mixed $setting
     */
    public function loadSnsSetting($key)
    {
        $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFFB); // use facebook config as default
        switch ($this->platform) {
            case ModuleSnsConst::PFFB:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFFB);
                break;
            case ModuleSnsConst::PFRR:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFRR);
                break;
            case ModuleSnsConst::PFSA:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFSA);
                break;
            case ModuleSnsConst::PFVK:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFVK);
                break;
            case ModuleSnsConst::PFAG:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFAG);
                break;
            case ModuleSnsConst::PFOGZ:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFOGZ);
                break;
            case ModuleSnsConst::PFTC:
            case ModuleSnsConst::PFQZ:
            case ModuleSnsConst::PFPY:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFTC);
                break;
            case ModuleSnsConst::PFSZ:
                $platformConfigName = self::getSnsConfigFileName(ModuleSnsConst::PFSZ);
                break;
        }
        return SzConfig::get()->loadAppConfig($platformConfigName, $key);
    }

    /**
     * Get sns platform specified config file name.
     * <pre>
     * ModuleSnsConst::MODULE_NAME . '_' . $platform
     * </pre>
     *
     * @param string $platform
     * @return string $name
     */
    public static function getSnsConfigFileName($platform)
    {
        return ModuleSnsConst::MODULE_NAME . '/' . ModuleSnsConst::MODULE_NAME . '_' . $platform;
    }

}